package cn.fintecher.gis.service;

import cn.fintecher.gis.entity.QUploadFile;
import cn.fintecher.gis.entity.UploadFile;
import cn.fintecher.gis.respository.UploadFileRepository;
import cn.fintecher.gis.utils.Snowflake;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by ChenChang on 2017/12/26.
 */
@Service("uploadFileService")
public class UploadFileService {
    private final Logger log = LoggerFactory.getLogger(UploadFileService.class);
    @Autowired
    private UploadFileRepository uploadFileRepository;
    @Value("${file.dir}")
    private String fileDir;

    @Value("${file.base-url}")
    private String baseUrl;
    @Autowired
    private Snowflake snowflake;

    public UploadFile findOne(String id) {
        UploadFile uploadFile = uploadFileRepository.findById(id).get();
//        uploadFile.setUrl(baseUrl + "/" + uploadFile.getFileName());
        return uploadFile;
    }

    public File findOneFile(String id) {
        UploadFile uploadFile = findOne(id);
        File file = new File(fileDir + "/" + uploadFile.getFileName());
        return file;
    }

    public File findOneFileByName(String fileName) {
        QUploadFile qUploadFile = QUploadFile.uploadFile;
        UploadFile uploadFile = uploadFileRepository.findOne(qUploadFile.fileName.contains(fileName)).get();
        File file = new File(fileDir + "/" + uploadFile.getFileName());
        return file;
    }

    public ResponseEntity<UploadFile> fileUpload(MultipartFile file) throws IOException {

        UploadFile uploadFile = fileUpload(file.getInputStream(), file.getOriginalFilename());
        return ResponseEntity.ok().body(uploadFile);

    }

    public UploadFile fileUpload(InputStream inputStream, String originalName) throws IOException {
        String extensionName = originalName.substring(originalName.lastIndexOf(".") + 1);
        String fileId = String.valueOf(snowflake.next());
        String fileName = fileId + "." + extensionName;
        saveToDisk(inputStream, extensionName, fileId);
        UploadFile uploadFile = saveUploadFile(fileId, fileName, originalName, extensionName);
        inputStream.close();
        return uploadFile;

    }

    private void saveToDisk(InputStream inputStream, String extensionName, String fileId) throws IOException {
        File outFile = new File(fileDir);
        if (!outFile.exists()) {
            outFile.mkdirs();
        }
        String fileName = fileId + "." + extensionName;
        OutputStream ot = new FileOutputStream(fileDir + "/" + fileName);
        byte[] buffer = new byte[1024];
        int len;
        while ((-1 != (len = inputStream.read(buffer)))) {
            ot.write(buffer, 0, len);
        }
        ot.close();
    }

    private UploadFile saveUploadFile(String fileId, String fileName
            , String originalName, String extensionName) {
        UploadFile uploadFile = new UploadFile();
        uploadFile.setOriginalName(originalName);
        uploadFile.setExtensionName(extensionName);
        uploadFile.setFileName(fileName);
        uploadFile.setId(fileId);
        uploadFile.setUrl(fileName);
        return uploadFileRepository.save(uploadFile);
    }

    public Multimap<String, UploadFile> unZipUploadFile(String fileId) throws IOException {
        UploadFile uploadFile = uploadFileRepository.findById(fileId).get();
        return unZipFileAndUpload(uploadFile);
    }

    public Multimap<String, UploadFile> unZipFileAndUpload(UploadFile uploadFile) {
        Multimap<String, UploadFile> fileMultimap = ArrayListMultimap.create();
        File zipFile = findOneFile(uploadFile.getId());
        String encoding = "GBK";
        /*if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
            encoding = "GBK";
        } else {
            encoding = "UTF-8";
        }*/
        String descDir = fileDir + "/" + uploadFile.getId();
        try (ZipArchiveInputStream inputStream = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)), encoding)) {
            File pathFile = new File(descDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            ZipArchiveEntry entry = null;
            String directoryStr = "";
            while ((entry = inputStream.getNextZipEntry()) != null) {
                if (entry.isDirectory()) {
                    directoryStr = entry.getName().replaceAll(" ", "");
                    File directory = new File(descDir, directoryStr);
                    log.debug("正在创建解压目录 - {}", directoryStr);
                    directory.mkdirs();
                } else {
                    OutputStream os = null;
                    File outfile = new File(descDir, entry.getName().replaceAll(" ", ""));
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(outfile));
                        //输出文件路径信息
                        log.info("解压文件的当前路径为:{}/{}", descDir, entry.getName());
                        IOUtils.copy(inputStream, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                    UploadFile file = fileUpload(new FileInputStream(outfile), outfile.getName());
                    fileMultimap.put(directoryStr, file);
                }
            }
            log.info("******************解压完毕********************");
        } catch (Exception e) {
            log.error("[unzip] 解压zip文件出错", e);
        }
        return fileMultimap;
    }

    public String unZipShpFile(String fileId) {
        UploadFile uploadFile = uploadFileRepository.findById(fileId).get();
        File zipFile = findOneFile(uploadFile.getId());
        String encoding = "GBK";
        /*if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) {
            encoding = "GBK";
        } else {
            encoding = "UTF-8";
        }*/
        String descDir = fileDir + "/" + uploadFile.getId();
        try (ZipArchiveInputStream inputStream = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)), encoding)) {
            File pathFile = new File(descDir);
            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            ZipArchiveEntry entry = null;
            String directoryStr = "";
            while ((entry = inputStream.getNextZipEntry()) != null) {
                if (entry.isDirectory()) {
                    directoryStr = entry.getName().replaceAll(" ", "");
                    File directory = new File(descDir, directoryStr);
                    log.debug("正在创建解压目录 - {}", directoryStr);
                    directory.mkdirs();
                } else {
                    OutputStream os = null;
                    File outfile = new File(descDir, entry.getName().replaceAll(" ", ""));
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(outfile));
                        //输出文件路径信息
                        log.info("解压文件的当前路径为:{}/{}", descDir, entry.getName());
                        IOUtils.copy(inputStream, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }

                }
            }
            log.info("******************解压完毕********************");
        } catch (Exception e) {
            log.error("[unzip] 解压zip文件出错", e);
        }
        return descDir;
    }


    private Map<String, String> getExcelOutputAttrs(Class clazz) {
        Map<String, String> map = new LinkedHashMap<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            map.put(field.getName(), field.getAnnotation(ApiModelProperty.class).notes());
        }
        return map;
    }


    public List<UploadFile> getUploadFile(String fileIds) {
        List<UploadFile> uploadFileList = new ArrayList<>();
        if (fileIds != null && !fileIds.isEmpty()) {
            String[] ids = fileIds.split(",");
            for (int i = 0; i < ids.length; i++) {
                UploadFile uploadFile = findOne(ids[i].toString());
                uploadFileList.add(uploadFile);
            }
        }
        return uploadFileList;
    }
}
